<template>
  <div>
    <el-button @click="getData">导出数据</el-button>
    <el-button @click="upData">导入数据</el-button>
    <div>
      <el-input v-model="input" placeholder="请输入节点名称" @change="setLabel"></el-input>
      <el-input v-model="inputArea" :rows="5" type="textarea" placeholder="请输入导入内容"></el-input>
    </div>
    <div id="container" style="width: 100%; height: 600px"></div>
  </div>
</template>

<script>
import { Graph, Shape } from "@antv/x6";
import { Stencil } from "@antv/x6-plugin-stencil";
import { Transform } from "@antv/x6-plugin-transform";
import { Selection } from "@antv/x6-plugin-selection";
import { Snapline } from "@antv/x6-plugin-snapline";
import { Keyboard } from "@antv/x6-plugin-keyboard";
import { Clipboard } from "@antv/x6-plugin-clipboard";
import { History } from "@antv/x6-plugin-history";
import insertCss from "insert-css";

export default {
  data() {
    return {
      input: "",
      inputArea: ""
    };
  },
  methods: {
    getData() {
      this.inputArea = JSON.stringify(this.graph.toJSON({ diff: true }));
    },
    upData() {
      // ...
      this.graph.fromJSON(JSON.parse(this.inputArea));
    },
    setLabel(value) {
      if (!this.activeNode) return;
      if (this.activeNode.shape == "edge") {
        this.activeNode.labels = value;
      } else {
        this.activeNode.attr("text/text", value);
      }
    }
  },
  mounted() {
    // 为了协助代码演示
    preWork();
    console.log(1);
    // #region 初始化画布
    const graph = new Graph({
      container: document.getElementById("graph-container"),
      grid: true,
      mousewheel: {
        enabled: true,
        zoomAtMousePosition: true,
        modifiers: "ctrl",
        minScale: 0.5,
        maxScale: 3
      },
      connecting: {
        router: "manhattan",
        connector: {
          name: "rounded",
          args: {
            radius: 8
          }
        },
        anchor: "center",
        connectionPoint: "anchor",
        allowBlank: false,
        snap: {
          radius: 20
        },
        createEdge() {
          return new Shape.Edge({
            attrs: {
              line: {
                stroke: "#A2B1C3",
                strokeWidth: 2,
                targetMarker: {
                  name: "block",
                  width: 12,
                  height: 8
                }
              }
            },
            zIndex: 0
          });
        },
        validateConnection({ targetMagnet }) {
          return !!targetMagnet;
        }
      },
      highlighting: {
        magnetAdsorbed: {
          name: "stroke",
          args: {
            attrs: {
              fill: "#5F95FF",
              stroke: "#5F95FF"
            }
          }
        }
      }
    });
    // #endregion

    // #region 使用插件
    graph
      .use(
        new Transform({
          resizing: true,
          rotating: true
        })
      )
      .use(
        new Selection({
          rubberband: true,
          showNodeSelectionBox: true
        })
      )
      .use(new Snapline())
      .use(new Keyboard())
      .use(new Clipboard())
      .use(new History());
    // #endregion

    // #region 初始化 stencil
    const stencil = new Stencil({
      title: "流程图",
      target: graph,
      stencilGraphWidth: 200,
      stencilGraphHeight: 180,
      collapsable: true,
      groups: [
        {
          title: "基础流程图",
          name: "group1"
        }
      ],
      layoutOptions: {
        columns: 2,
        columnWidth: 80,
        rowHeight: 55
      }
    });
    document.getElementById("stencil").appendChild(stencil.container);
    // #endregion

    // #region 快捷键与事件
    graph.bindKey(["meta+c", "ctrl+c"], () => {
      const cells = graph.getSelectedCells();
      if (cells.length) {
        graph.copy(cells);
      }
      return false;
    });
    graph.bindKey(["meta+x", "ctrl+x"], () => {
      const cells = graph.getSelectedCells();
      if (cells.length) {
        graph.cut(cells);
      }
      return false;
    });
    graph.bindKey(["meta+v", "ctrl+v"], () => {
      if (!graph.isClipboardEmpty()) {
        const cells = graph.paste({ offset: 32 });
        graph.cleanSelection();
        graph.select(cells);
      }
      return false;
    });

    // undo redo
    graph.bindKey(["meta+z", "ctrl+z"], () => {
      if (graph.canUndo()) {
        graph.undo();
      }
      return false;
    });
    graph.bindKey(["meta+shift+z", "ctrl+shift+z"], () => {
      if (graph.canRedo()) {
        graph.redo();
      }
      return false;
    });

    // select all
    graph.bindKey(["meta+a", "ctrl+a"], () => {
      const nodes = graph.getNodes();
      if (nodes) {
        graph.select(nodes);
      }
    });

    // delete
    graph.bindKey("backspace", () => {
      const cells = graph.getSelectedCells();
      if (cells.length) {
        graph.removeCells(cells);
      }
    });

    // zoom
    graph.bindKey(["ctrl+1", "meta+1"], () => {
      const zoom = graph.zoom();
      if (zoom < 1.5) {
        graph.zoom(0.1);
      }
    });
    graph.bindKey(["ctrl+2", "meta+2"], () => {
      const zoom = graph.zoom();
      if (zoom > 0.5) {
        graph.zoom(-0.1);
      }
    });

    // 控制连接桩显示/隐藏
    const showPorts = (ports, show) => {
      for (let i = 0, len = ports.length; i < len; i += 1) {
        ports[i].style.visibility = show ? "visible" : "hidden";
      }
    };
    graph.on("node:mouseenter", () => {
      const container = document.getElementById("graph-container");
      const ports = container.querySelectorAll(".x6-port-body");
      showPorts(ports, true);
    });
    graph.on("node:mouseleave", () => {
      const container = document.getElementById("graph-container");
      const ports = container.querySelectorAll(".x6-port-body");
      showPorts(ports, false);
    });

    graph.on("node:click", ({ node }) => {
      //
      this.activeNode = node;
      this.input = node.label;
      // rect.attr('label/text', 'hello')
    });
    graph.on("edge:click", ({ edge }) => {
      //
      this.activeNode = edge;
      this.input = edge.label;
    });

    // #endregion

    // #region 初始化图形
    const ports = {
      groups: {
        top: {
          position: "top",
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: "#5F95FF",
              strokeWidth: 1,
              fill: "#fff",
              style: {
                visibility: "hidden"
              }
            }
          }
        },
        right: {
          position: "right",
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: "#5F95FF",
              strokeWidth: 1,
              fill: "#fff",
              style: {
                visibility: "hidden"
              }
            }
          }
        },
        bottom: {
          position: "bottom",
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: "#5F95FF",
              strokeWidth: 1,
              fill: "#fff",
              style: {
                visibility: "hidden"
              }
            }
          }
        },
        left: {
          position: "left",
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: "#5F95FF",
              strokeWidth: 1,
              fill: "#fff",
              style: {
                visibility: "hidden"
              }
            }
          }
        }
      },
      items: [
        {
          group: "top"
        },
        {
          group: "right"
        },
        {
          group: "bottom"
        },
        {
          group: "left"
        }
      ]
    };

    Graph.registerNode(
      "custom-rect",
      {
        inherit: "rect",
        width: 66,
        height: 36,
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: "#5F95FF",
            fill: "#EFF4FF"
          },
          text: {
            fontSize: 12,
            fill: "#262626"
          }
        },
        ports: { ...ports }
      },
      true
    );

    Graph.registerNode(
      "custom-circle",
      {
        inherit: "circle",
        width: 45,
        height: 45,
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: "#5F95FF",
            fill: "#EFF4FF"
          },
          text: {
            fontSize: 12,
            fill: "#262626"
          }
        },
        ports: { ...ports }
      },
      true
    );

    const r1 = graph.createNode({
      shape: "custom-circle",
      width: 40,
      height: 40,
      attrs: {
        body: {
          fill: "#1bf551"
        },
        text: {
          fontSize: 12,
          fill: "#262626"
        }
      }
    });
    const r2 = graph.createNode({
      shape: "custom-rect",
      label: "未开始",
      attrs: {
        body: {
          rx: 6,
          ry: 6,
          stroke: "#000",
          fill: "#a0a5a1",
          strokeWidth: 1
        }
      }
    });
    const r3 = graph.createNode({
      shape: "custom-rect",
      label: "正在进行",
      attrs: {
        body: {
          rx: 6,
          ry: 6,
          stroke: "#f3f319",
          fill: "#f0f0ac",
          strokeWidth: 1
        }
      }
    });
    const r4 = graph.createNode({
      shape: "custom-rect",
      label: "已完成",
      attrs: {
        body: {
          rx: 6,
          ry: 6,
          stroke: "#0feb30",
          fill: "#b5f1be",
          strokeWidth: 1
        }
      }
    });
    const r5 = graph.createNode({
      shape: "custom-rect",
      label: "子流程",
      attrs: {
        body: {
          rx: 6,
          ry: 6,
          stroke: "#5F95FF",
          fill: "#EFF4FF",
          strokeWidth: 1
        }
      }
    });
    stencil.load([r1, r2, r3, r4, r5], "group1");

    // #endregion
    function preWork() {
      // 这里协助演示的代码，在实际项目中根据实际情况进行调整
      const container = document.getElementById("container");
      const stencilContainer = document.createElement("div");
      stencilContainer.id = "stencil";
      const graphContainer = document.createElement("div");
      graphContainer.id = "graph-container";
      container.appendChild(stencilContainer);
      container.appendChild(graphContainer);

      insertCss(`
    #container {
      display: flex;
      border: 1px solid #dfe3e8;
    }
    #stencil {
      width: 180px;
      height: 100%;
      position: relative;
      border-right: 1px solid #dfe3e8;
    }
    #graph-container {
      width: calc(100% - 180px);
      height: 100%;
    }
    .x6-widget-stencil  {
      background-color: #fff;
    }
    .x6-widget-stencil-title {
      background-color: #fff;
    }
    .x6-widget-stencil-group-title {
      background-color: #fff !important;
    }
    .x6-widget-transform {
      margin: -1px 0 0 -1px;
      padding: 0px;
      border: 1px solid #239edd;
    }
    .x6-widget-transform > div {
      border: 1px solid #239edd;
    }
    .x6-widget-transform > div:hover {
      background-color: #3dafe4;
    }
    .x6-widget-transform-active-handle {
      background-color: #3dafe4;
    }
    .x6-widget-transform-resize {
      border-radius: 0;
    }
    .x6-widget-selection-inner {
      border: 1px solid #239edd;
    }
    .x6-widget-selection-box {
      opacity: 0;
    }
  `);
    }

    this.graph = graph;
  }
};
</script>

<style>
</style>